#include <jni.h>
#include <btBulletDynamicsCommon.h>

// Rajout des bibliothèques
#pragma comment (lib, "BulletCollision.lib")
#pragma comment (lib, "BulletDynamics.lib")
#pragma comment (lib, "LinearMath.lib")

/* For JNI: C++ compiler need this */
extern "C" {

	#define BALL_SIZE 1
	#define START_POS_Z 0

	btAlignedObjectArray<btCollisionShape*>	m_collisionShapes;
	btBroadphaseInterface*	m_broadphase;
	btCollisionDispatcher*	m_dispatcher;
	btConstraintSolver*	m_solver;
	btDefaultCollisionConfiguration* m_collisionConfiguration;
	btDefaultMotionState* barre1;
	btDefaultMotionState* barre2;
	int hauteur_ecran;
	int largeur_ecran;
	int largeur_barre;
	int hauteur_barre;
	int speed_barre;
	btDiscreteDynamicsWorld* m_dynamicsWorld;
	btRigidBody* ball;

	jint Java_com_example_pong_MainActivity_init( JNIEnv*  env, jobject  thiz,
		jint LARGEUR_BARRE, jint HAUTEUR_BARRE, jint LARGEUR_ECRAN, jint HAUTEUR_ECRAN,
		jint START_POS_X, jint START_POS_Y, jint speedX, jint speedY, jint speedBarre)
	{

		int start_pos_x = START_POS_X;
		int start_pos_y = START_POS_Y;
		largeur_ecran = LARGEUR_ECRAN;
		hauteur_ecran = HAUTEUR_ECRAN;
		hauteur_barre = HAUTEUR_BARRE;
		largeur_barre = LARGEUR_BARRE;
		int speed_x = speedX;
		int speed_y = speedY;
		speed_barre = speedBarre;

		m_collisionConfiguration = new btDefaultCollisionConfiguration();

		m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
		m_broadphase = new btDbvtBroadphase();

		m_solver = new btSequentialImpulseConstraintSolver;

		m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);

		m_dynamicsWorld->setGravity(btVector3(0,0,0));

		//RAJOUT DES DEUX BORDS
		btCollisionShape* border = new btBoxShape( btVector3(2500, 10, 2500) );
		btCollisionShape* shape_barre = new btBoxShape( btVector3((LARGEUR_BARRE/2),(HAUTEUR_BARRE/2),20) );
		btCollisionShape* no_axe_z_shape = new btBoxShape( btVector3(2500,2500,2));

		btTransform myTransform;
		myTransform.setIdentity();
		myTransform.setOrigin( btVector3(0,10,0) );

		btDefaultMotionState* groundMotionState = new btDefaultMotionState(myTransform);
		btRigidBody::btRigidBodyConstructionInfo info(0, groundMotionState, border, btVector3(0,0,0));
		info.m_restitution = 1;
		info.m_friction=0;
		btRigidBody* bot_border = new btRigidBody(info);
		m_dynamicsWorld->addRigidBody(bot_border);
		m_collisionShapes.push_back(border);

		/* Les murs pour ne pas avoir de déplacement sur l'axe z */

		//La position:
		myTransform.setIdentity();
		myTransform.setOrigin( btVector3(0,0,3) );
		//Axe z avant
		btDefaultMotionState* block_axe_z_1 = new btDefaultMotionState(myTransform);
		btRigidBody::btRigidBodyConstructionInfo info_axe_z_1(0, block_axe_z_1, no_axe_z_shape, btVector3(0,0,0));
		info_axe_z_1.m_restitution = 1;
		info_axe_z_1.m_friction=0;
		btRigidBody* no_axe_z_body1 = new btRigidBody(info_axe_z_1);
		m_dynamicsWorld->addRigidBody(no_axe_z_body1);
		m_collisionShapes.push_back(no_axe_z_shape);

		//La position:
		myTransform.setIdentity();
		myTransform.setOrigin( btVector3(0,0,-3) );
		//Axe z arriere
		btDefaultMotionState* block_axe_z_2 = new btDefaultMotionState(myTransform);
		btRigidBody::btRigidBodyConstructionInfo info_axe_z_2(0, block_axe_z_2, no_axe_z_shape, btVector3(0,0,0));
		info_axe_z_2.m_restitution = 1;
		info_axe_z_2.m_friction=0;
		btRigidBody* no_axe_z_body2 = new btRigidBody(info_axe_z_2);
		m_dynamicsWorld->addRigidBody(no_axe_z_body2);
		m_collisionShapes.push_back(no_axe_z_shape);
		/**************************/

		myTransform.setIdentity();
		myTransform.setOrigin( btVector3(0,HAUTEUR_ECRAN-10,0) );

		btDefaultMotionState* groundMotionState2 = new btDefaultMotionState(myTransform);
		btRigidBody::btRigidBodyConstructionInfo info2(0, groundMotionState2, border, btVector3(0,0,0));
		info2.m_restitution = 1;
		info2.m_friction=0;
		btRigidBody* top_border = new btRigidBody(info2);
		m_dynamicsWorld->addRigidBody(top_border);

		//RAJOUT DE LA BALLE;
		btSphereShape* ballShape = new btSphereShape(BALL_SIZE);
		btTransform ballTransform;
		ballTransform.setIdentity();
		ballTransform.setOrigin(btVector3(start_pos_x,start_pos_y,START_POS_Z));
		btScalar mass = 1;
		btVector3 localInertia(0,5,0);
		ballShape->calculateLocalInertia(mass,localInertia);
		btDefaultMotionState* myMotionState = new btDefaultMotionState(ballTransform);

		btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,ballShape,localInertia);
		rbInfo.m_friction=0;
		rbInfo.m_restitution = 1;
		ball = new btRigidBody(rbInfo);
		m_dynamicsWorld->addRigidBody(ball);
		ball->activate(true);
		ball->applyForce(btVector3(speed_x,speed_y,0),btVector3(start_pos_x,start_pos_y,START_POS_Z));


		/* Objets de l'utilisateurs (barres) */

		//Position:
		myTransform.setIdentity();
		myTransform.setOrigin( btVector3(10+(LARGEUR_BARRE/2),(2*HAUTEUR_BARRE)+(HAUTEUR_BARRE/2),0));

		//Barre gauche;
		barre1 = new btDefaultMotionState(myTransform);
		btRigidBody::btRigidBodyConstructionInfo info3(0, barre1, shape_barre, btVector3(0,0,0));
		info3.m_restitution = 1;
		info3.m_friction=0;
		btRigidBody* barre1_body = new btRigidBody(info3);
			barre1_body->setCollisionFlags( barre1_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
			barre1_body->setActivationState(DISABLE_DEACTIVATION);
		m_dynamicsWorld->addRigidBody(barre1_body);

		//Position:
		myTransform.setIdentity();
		myTransform.setOrigin( btVector3((LARGEUR_ECRAN-10-(LARGEUR_BARRE/2)),HAUTEUR_BARRE+(HAUTEUR_BARRE/2),0));

		//Barre droite;
		barre2 = new btDefaultMotionState(myTransform);
		btRigidBody::btRigidBodyConstructionInfo info4(0, barre2, shape_barre, btVector3(0,0,0));
		info4.m_restitution = 1;
		info4.m_friction=0;
		btRigidBody* barre2_body = new btRigidBody(info4);
			barre2_body->setCollisionFlags( barre2_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
			barre2_body->setActivationState(DISABLE_DEACTIVATION);
		m_dynamicsWorld->addRigidBody(barre2_body);
	
		return 0;
	}
	
	jint Java_com_example_pong_MainActivity_exitPhysics( JNIEnv*  env, jobject  thiz)
	{
		//cleanup in the reverse order of creation/initialization

		//remove the rigidbodies from the dynamics world and delete them
		for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
		{
			btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
			btRigidBody* body = btRigidBody::upcast(obj);
			if (body && body->getMotionState())
			{
				delete body->getMotionState();
			}
			m_dynamicsWorld->removeCollisionObject( obj );
			delete obj;
		}

		//delete collision shapes
		for (int j=0;j<m_collisionShapes.size();j++)
		{
			btCollisionShape* shape = m_collisionShapes[j];
			delete shape;
		}
		m_collisionShapes.clear();
		delete m_dynamicsWorld;
		delete m_solver;
		delete m_broadphase;
		delete m_dispatcher;
		delete m_collisionConfiguration;

		return 0;
	}

	jobject Java_com_example_pong_MainActivity_simulationNext( JNIEnv*  env, jobject  thiz)
	{
		//Simulation d'un pas.
		m_dynamicsWorld->stepSimulation(1/10.f,10);

		//Recuperation de la nouvelle position de la balle.
		btTransform trans;
		ball->getMotionState()->getWorldTransform(trans);
		jint fill[3];
		jintArray res;

		fill[0] = (jint)trans.getOrigin().getX();
		fill[1] = (jint)trans.getOrigin().getY();
		fill[2] = (jint)trans.getOrigin().getZ();

		res = env->NewIntArray(3);
		env->SetIntArrayRegion(res ,0, 3, fill);

	    return res;
	}

	jint Java_com_example_pong_MainActivity_upload( JNIEnv*  env, jobject  thiz,
			jint joueur, jint direction){
	
		int player = joueur;
		int direct = direction;
		if(direct==1||direct==2){
			btTransform bt,bt2;

			if(player==1){
				barre1->getWorldTransform(bt);
				bt2.setIdentity();

				if(direct==1)
					bt2.setOrigin(bt.getOrigin()+btVector3(0,speed_barre,0));
				if(direct==2)
					bt2.setOrigin(bt.getOrigin()+btVector3(0,-speed_barre,0));

				if((direct==1 && (bt.getOrigin()+btVector3(0,speed_barre,0)).getY()+hauteur_barre/2<=hauteur_ecran-20)
				|| (direct==2 && (bt.getOrigin()+btVector3(0,-speed_barre,0)).getY()-hauteur_barre/2))
					barre1->setWorldTransform(bt2);
			}
			if(player==2){
				barre2->getWorldTransform(bt);
				bt2.setIdentity();
			
				if(direct==1)
					bt2.setOrigin(bt.getOrigin()+btVector3(0,speed_barre,0));
				if(direct==2)
					bt2.setOrigin(bt.getOrigin()+btVector3(0,-speed_barre,0));

				if((direct==1 && (bt.getOrigin()+btVector3(0,speed_barre,0)).getY()+hauteur_barre/2<=hauteur_ecran-20)
				|| (direct==2 && (bt.getOrigin()+btVector3(0,-speed_barre,0)).getY()-hauteur_barre/2))
					barre2->setWorldTransform(bt2);
			}
		}
		return 0;
	}

}
